// Two pass assembler with absolute addressing (for SIC machine).

#include"hexdec.cpp"
#include"source.cpp"
#include"optbedit.cpp"

class sym
{private:
   char symbol[10];
   char addr[5];
   int left,right;
   public:
    sym() 			     { left=0; right=0;  }
    void setsymbol(char* x)          { strcpy(symbol,x); }
    void setaddr(char *x)            { strcpy(addr,x); }
    void setleft(int x)              { left=x;}
    void setright(int x)             { right=x;}
    char* retsymbol()                { return symbol;}
    char* retaddr()                  { return addr;}
    int retleft()                    { return left;}
    int retright()                   { return right; }

   void outdata(int i)
     {
      gotoxy(2,i+4);      cout<<symbol;
      gotoxy(18,i+4);     cout<<addr;
     }
}; // end of class

void addsym(sym nu)                   // add an object to the symtab
{
 sym root,t,temp;
 int j,n;
 static int i=0;
 int ptr,prev;
 fstream os;

 os.open("symtab.dat",ios::in|ios::out|ios::binary);
 os.seekg(0,ios::beg);
 os.read((char*)&root,sizeof(root));
 if(root.retleft()==0)
  {
     i++;
     os.seekp(1*sizeof(sym),ios::beg);
     os.write((char*)&nu,sizeof(nu));
     os.seekg(0,ios::beg);
     os.read((char*)&t,sizeof(t));
     temp.setsymbol(" ");
     temp.setaddr(" ");
     temp.setleft(1);
     temp.setright(0);
     os.seekp(0,ios::beg);
     os.write((char*)&temp,sizeof(temp));
  }//end of if
 else
  {  ptr=1;
     i++;
     while(ptr!=0)
     {
       os.seekg(ptr*sizeof(sym),ios::beg);
       os.read((char*)&t,sizeof(t));
       prev=ptr;
       if(strcmpi(nu.retsymbol(),t.retsymbol()) <= 0 ) ptr=t.retleft();
       else ptr=t.retright();
     }  // end of while

     if(strcmpi(nu.retsymbol(),t.retsymbol()) <= 0 )
	  {
	    os.seekp(i*sizeof(sym),ios::beg);
	    os.write((char*)&nu,sizeof(nu));
	    os.seekg(prev*sizeof(sym),ios::beg);
	    os.read((char*)&t,sizeof(t));
	    temp.setsymbol(t.retsymbol());
	    temp.setaddr(t.retaddr());
	    temp.setleft(i);
	    temp.setright(t.retright());
	    os.seekp(prev*sizeof(sym),ios::beg);
	    os.write((char*)&temp,sizeof(temp));
	  }
	 else
	  {
	    os.seekp(i*sizeof(sym),ios::beg);
	    os.write((char*)&nu,sizeof(nu));
	    os.seekg(prev*sizeof(sym),ios::beg);
	    os.read((char*)&t,sizeof(t));
	    temp.setsymbol(t.retsymbol());
	    temp.setaddr(t.retaddr());
	    temp.setleft(t.retleft());
	    temp.setright(i);
	    os.seekp(prev*sizeof(sym),ios::beg);
	    os.write((char*)&temp,sizeof(temp));
	   }
    }// end of else
    os.close();
}

int searchsym(char str[])                              // search
{
 ifstream os;
 sym t;
 int temp,ptr=1;

 os.open("symtab.dat",ios::in|ios::binary);
 os.seekg(0,ios::beg);
 os.read((char*)&t,sizeof(t));
 if(t.retleft()==0) {os.close(); return 0;}

 while(ptr!=0)
 { os.seekg(ptr*sizeof(sym),ios::beg);
   os.read((char*)&t,sizeof(t));
   if(strcmpi(str,t.retsymbol()) < 0)
      { ptr=t.retleft(); }
   else if(strcmpi(str,t.retsymbol()) == 0)
      { strcpy(str,t.retaddr());  os.close();  return 1;   }
   else  { ptr=t.retright();   }
 }  // end of while loop

 return 0;
} // end of search

void pass1()                                   // pass1
{
 sym root,t;       //object of symtab
 oprec  op;        // object of source file
 ifstream sfile;   // source file pointer
 int i,j,n;
 char locctr[10],staddr[10],temp[10];
 char length[10];

 sfile.open("source.dat",ios::in|ios::binary);
 sfile.read((char*)&op,sizeof(op));
 if(strcmpi(op.retmnemonic(),"start")==0)
  {strcpy(staddr,op.retoperand());
   strcpy(locctr,op.retoperand());
   sfile.read((char*)&op,sizeof(op));}
 else
  {strcpy(locctr,"0"); }

 while(strcmpi(op.retmnemonic(),"end"))
 {
  if(strcmpi(op.retlabel(),"/")!=0)
   { strcpy(temp,op.retlabel());
     if(searchsym(temp)==0)
	{root.setsymbol(op.retlabel()); root.setaddr(locctr); addsym(root);}
      else
	{cout<<"Duplicate label"<<op.retlabel(); getch(); exit(0);}
   }// end of if search label

   strcpy(temp,op.retmnemonic());
   // search for opcode
   if(searchop(temp)!=0) {n=3; hex(locctr,'+',n);}
   else if(strcmpi(temp,"word")==0)
		    {n=3; hex(locctr,'+',n);}
   else if(strcmpi(temp,"resw")==0)
		    {n=atoi(op.retoperand()); n*=3; hex(locctr,'+',n);  }
   else if(strcmpi(temp,"byte")==0)
		    {n=strlen(op.retoperand()); n-=3; hex(locctr,'+',n); }
   else if(strcmpi(temp,"resb")==0)
		    {n=atoi(op.retoperand()); hex(locctr,'+',n); }
   else
		    {cout<<" Error..."; getch(); exit(0); }
   sfile.read((char*)&op,sizeof(op));
 }// end of while loop

 n=atoi(staddr); strcpy(length,locctr); hex(length,'-',n);
}// end of pass1

void pass2()
{
 sym root,t;       //object of symtab
 outrec out;       // object of outfile
 oprec  op;        // object of source file
 ifstream sfile;   // source file pointer
 ofstream ofile;   // outfile pointer
 int i,j,n;
 char locctr[10],staddr[10],tempop[10];
 char length[10],tempsym[10];
 ofile.open("outfile.dat",ios::out|ios::binary);

 sfile.open("source.dat",ios::in|ios::binary);
 sfile.read((char*)&op,sizeof(op));
 if(strcmpi(op.retmnemonic(),"start")==0)
  {out.setlabel(op.retlabel());	    out.setmnemonic(op.retmnemonic());
   out.setoperand(op.retoperand()); out.setobjcode("000000");
   ofile.write((char*)&out,sizeof(out));  sfile.read((char*)&op,sizeof(op));  }

 while(strcmpi(op.retmnemonic(),"end"))
  {// search optab for opcode
   strcpy(tempop,op.retmnemonic());
   if(searchop(tempop)!=0)
   {
    if(strcmpi(op.retoperand(),"/")!=0)
     {strcpy(tempsym,op.retoperand());
      if(searchsym(tempsym)!=0)
	 {strcat(tempop,tempsym);
	  out.setlabel(op.retlabel());     out.setmnemonic(op.retmnemonic());
	  out.setoperand(op.retoperand()); out.setobjcode(tempop);
	  ofile.write((char*)&out,sizeof(out));}
      else
	 {cout<<"undefined symbol"<<op.retoperand(); getch(); exit(0);}
     }
    else
     { out.setlabel(op.retlabel());       out.setmnemonic(op.retmnemonic());
      out.setoperand(op.retoperand());    strcat(tempop,"0000");
      out.setobjcode(tempop);
      ofile.write((char*)&out,sizeof(out)); }// end of if /
  }// end of if optab

  else if(strcmpi(tempop,"word")==0)
   {n=atoi(op.retoperand());
    strcpy(tempop,"0000");
    hex(tempop,'+',n);
    char temp[10];
    strcpy(temp,"00");
    strcat(temp,tempop);

    out.setlabel(op.retlabel());	out.setmnemonic(op.retmnemonic());
    out.setoperand(op.retoperand());    out.setobjcode(temp);
    ofile.write((char*)&out,sizeof(out));
   }

  else if(strcmpi(tempop,"byte")==0)
   {
       char t[10];
       strcpy(t,op.retoperand());
       int l=strlen(t);
       for(i=2;i<l-1;i++)
	{tempsym[i-2]=t[i];}   tempsym[l-3]='\0';

       out.setlabel(op.retlabel());       out.setmnemonic(op.retmnemonic());
       out.setoperand(op.retoperand());   out.setobjcode(tempsym);
       ofile.write((char*)&out,sizeof(out));
  }// end of if-else-if
   sfile.read((char*)&op,sizeof(op));
 }// end of while loop
   out.setlabel(op.retlabel());  	out.setmnemonic(op.retmnemonic());
   out.setoperand(op.retoperand());   	out.setobjcode("");
   ofile.write((char*)&out,sizeof(out));
   sfile.close();   ofile.close();
}//end of pass2

void main()
{
	ifstream stab,ofile;
	ofstream s;
	sym t;
	outrec o;
	int i=0,j=0;

	// following is necessary to keep the root node
	s.open("symtab.dat",ios::out|ios::binary);
	t.setsymbol(" "); t.setaddr(" "); t.setleft(0);	t.setright(0);
	s.write((char*)&t,sizeof(t));s.close();

	pass1(); clrscr();

	cout<<"--- SYMBOL TABLE ENTRIES --- End Of Pass 1\n";
	stab.open("symtab.dat",ios::in|ios::binary);
	while(!stab.eof())
	 { stab.read((char*)&t,sizeof(t));
	  if(!stab.eof())
	   {t.outdata(i); i++;}
	 }
	stab.close();
	getch();

	pass2(); clrscr();
	cout<<"--- End of Pass 2 ---------------------------";
	cout<<"\n LABEL      MNEMONIC       OPERAND    OBJCODE";
	cout<<"\n---------------------------------------------";

	i=0; ofile.open("outfile.dat",ios::in|ios::binary);
	while(!ofile.eof())
	{
	 ofile.read((char*)&o,sizeof(o));
	 if(!ofile.eof())
	  {
	   o.display(i); i++;
	   if(i==19)
	    {i=0;	getch();	clrscr();
	     cout<<"--- End Of Pass 2 ---------------------------";
	     cout<<"\n LABEL      MNEMONIC       OPERAND    OBJCODE";
	     cout<<"\n---------------------------------------------";}
	  }
	} ofile.close();
	cout<<"\n---------------------------------------------";getch();
}